package org.jeecg.modules.business.takestockplan.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.constant.FillRuleConstant;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.FillRuleUtil;
import org.jeecg.modules.basic.material.entity.BasicMaterial;
import org.jeecg.modules.basic.material.service.IBasicMaterialService;
import org.jeecg.modules.basic.warehouse.entity.WmsBasicWarehouse;
import org.jeecg.modules.basic.warehouse.entity.WmsBasicWarehouseArea;
import org.jeecg.modules.basic.warehouse.entity.WmsBasicWarehouseAreaLocation;
import org.jeecg.modules.basic.warehouse.mapper.WmsBasicWarehouseAreaLocationMapper;
import org.jeecg.modules.basic.warehouse.mapper.WmsBasicWarehouseAreaMapper;
import org.jeecg.modules.basic.warehouse.mapper.WmsBasicWarehouseMapper;
import org.jeecg.modules.business.repertory.entity.WmsRepertory;
import org.jeecg.modules.business.repertory.mapper.WmsRepertoryMapper;
import org.jeecg.modules.business.takestockplan.entity.*;
import org.jeecg.modules.business.takestockplan.entity.VO.TakeStockPlanExecuteMaterialVO;
import org.jeecg.modules.business.takestockplan.entity.VO.TakeStockPlanExecuteVO;
import org.jeecg.modules.business.takestockplan.entity.constant.TakeStockPlanStatusConstant;
import org.jeecg.modules.business.takestockplan.entity.constant.TakeStockResultConstant;
import org.jeecg.modules.business.takestockplan.mapper.TakeStockPlanDifferenceMapper;
import org.jeecg.modules.business.takestockplan.mapper.TakeStockPlanDifferenceMaterialMapper;
import org.jeecg.modules.business.takestockplan.mapper.TakeStockPlanExecuteMapper;
import org.jeecg.modules.business.takestockplan.service.*;
import org.jeecg.modules.flow.record.service.IWmsFlowMainService;
import org.jeecg.modules.flow.record.service.IWmsFlowRecordService;
import org.jeecgframework.poi.excel.ExcelImportUtil;
import org.jeecgframework.poi.excel.entity.ImportParams;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description: 盘点差异处理单
 * @Author: jeecg-boot
 * @Date:   2023-11-23
 * @Version: V1.0
 */
@Service
public class TakeStockPlanDifferenceServiceImpl extends ServiceImpl<TakeStockPlanDifferenceMapper, TakeStockPlanDifference> implements ITakeStockPlanDifferenceService {

	@Autowired
	private TakeStockPlanDifferenceMapper takeStockPlanDifferenceMapper;
	@Autowired
	private TakeStockPlanDifferenceMaterialMapper takeStockPlanDifferenceMaterialMapper;
	@Autowired
	private TakeStockPlanExecuteMapper takeStockPlanExecuteMapper;
	@Autowired
	private ITakeStockResultService takeStockResultService;
	@Autowired
	private IBasicMaterialService basicMaterialService;
	@Autowired
	private WmsBasicWarehouseMapper warehouseMapper;
	@Autowired
	private WmsBasicWarehouseAreaMapper warehouseAreaMapper;
	@Autowired
	private WmsBasicWarehouseAreaLocationMapper warehouseAreaLocationMapper;
	@Autowired
	private WmsRepertoryMapper repertoryMapper;
	@Autowired
	private ITakeStockPlanExecuteService takeStockPlanExecuteService;
	@Autowired
	private ITakeStockPlanDifferenceMaterialService takeStockPlanDifferenceMaterialService;
	@Autowired
	private IWmsFlowRecordService flowRecordService;
	@Autowired
	private IWmsFlowMainService flowMainService;
	@Autowired
	private ITakeStockPlanService takeStockPlanService;
	
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void saveMain(TakeStockPlanDifference takeStockPlanDifference, List<TakeStockPlanDifferenceMaterial> wmsTakeStockPlanDifferenceMaterialList) {
		LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
		takeStockPlanDifference.setOrganization(sysUser.getOrgCode());
		takeStockPlanDifferenceMapper.insert(takeStockPlanDifference);
		if(wmsTakeStockPlanDifferenceMaterialList!=null && wmsTakeStockPlanDifferenceMaterialList.size()>0) {
			for(TakeStockPlanDifferenceMaterial entity:wmsTakeStockPlanDifferenceMaterialList) {
				//外键设置
				entity.setTakeStockPlanDifferenceId(takeStockPlanDifference.getId());
				takeStockPlanDifferenceMaterialMapper.insert(entity);
			}
		}
		// 更新盘点作业的已生成盘点差异处理单字段
		TakeStockPlanExecute stockPlanExecute = takeStockPlanExecuteMapper.selectById(takeStockPlanDifference.getTakeStockPlanExecuteId());
		takeStockPlanExecuteService.update(new LambdaUpdateWrapper<TakeStockPlanExecute>()
				.eq(TakeStockPlanExecute::getWmsTakeStockPlanId, stockPlanExecute.getWmsTakeStockPlanId())
				.set(TakeStockPlanExecute::getGenerateFlag, "1"));
		// 更新盘点任务已生成盘点差异处理单字段
		takeStockPlanService.update(new LambdaUpdateWrapper<TakeStockPlan>()
				.eq(TakeStockPlan::getId, stockPlanExecute.getWmsTakeStockPlanId())
				.set(TakeStockPlan::getGenerateFlag, "1"));
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void updateMain(TakeStockPlanDifference takeStockPlanDifference,List<TakeStockPlanDifferenceMaterial> wmsTakeStockPlanDifferenceMaterialList) {
		takeStockPlanDifferenceMapper.updateById(takeStockPlanDifference);
		
		//1.先删除子表数据
		takeStockPlanDifferenceMaterialMapper.deleteByMainId(takeStockPlanDifference.getId());
		
		//2.子表数据重新插入
		if(wmsTakeStockPlanDifferenceMaterialList!=null && wmsTakeStockPlanDifferenceMaterialList.size()>0) {
			for(TakeStockPlanDifferenceMaterial entity:wmsTakeStockPlanDifferenceMaterialList) {
				//外键设置
				entity.setTakeStockPlanDifferenceId(takeStockPlanDifference.getId());
				takeStockPlanDifferenceMaterialMapper.insert(entity);
			}
		}
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void delMain(String id) {
		TakeStockPlanDifference byId = this.getById(id);
		// 更新盘点作业的已生成盘点差异处理单字段
		TakeStockPlanExecute stockPlanExecute = takeStockPlanExecuteMapper.selectById(byId.getTakeStockPlanExecuteId());
		takeStockPlanExecuteService.update(new LambdaUpdateWrapper<TakeStockPlanExecute>()
				.eq(TakeStockPlanExecute::getWmsTakeStockPlanId, stockPlanExecute.getWmsTakeStockPlanId())
				.set(TakeStockPlanExecute::getGenerateFlag, "0"));
		// 更新盘点任务已生成盘点差异处理单字段
		takeStockPlanService.update(new LambdaUpdateWrapper<TakeStockPlan>()
				.eq(TakeStockPlan::getId, stockPlanExecute.getWmsTakeStockPlanId())
				.set(TakeStockPlan::getGenerateFlag, "0"));
		// 盘点作业节点状态回退
//		List<WmsFlowRecord> flowList = flowRecordService.list(new LambdaQueryWrapper<WmsFlowRecord>()
//				.eq(WmsFlowRecord::getInfoId, byId.getTakeStockPlanExecuteId())
//				.orderByDesc(WmsFlowRecord::getSort));
//		WmsFlowRecord end = flowList.get(0);
//		WmsFlowRecord finish = flowList.get(1);
//		if (end.getStatus().equals(200)) {
//			end.setStatus(0);
//			flowRecordService.updateById(end);
//			finish.setStatus(1);
//			flowRecordService.updateById(finish);
//			// 变更当前节点信息
//			WmsFlowMain flowMain = flowMainService.getOne(new LambdaQueryWrapper<WmsFlowMain>()
//					.eq(WmsFlowMain::getInfoId, byId.getTakeStockPlanExecuteId())
//					.last("limit 1"));
//			flowMain.setCurrentStep(finish.getFlowCode());
//			flowMain.setCurrentStepName(finish.getFlowName());
//			flowMain.setCurrentStatus(1);
//			flowMainService.updateById(flowMain);
//		}

		takeStockPlanDifferenceMaterialMapper.deleteByMainId(id);
		takeStockPlanDifferenceMapper.deleteById(id);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void delBatchMain(Collection<? extends Serializable> idList) {
		for(Serializable id:idList) {
			takeStockPlanDifferenceMaterialMapper.deleteByMainId(id.toString());
			takeStockPlanDifferenceMapper.deleteById(id);
		}
	}

	/**
	 * 分页
	 * @param page
	 * @param takeStockPlanDifference
	 * @return
	 */
	@Override
	public Page<TakeStockPlanExecuteVO> listByPage(Page<TakeStockPlanExecuteVO> page, TakeStockPlanExecuteVO takeStockPlanDifference) {
		return page.setRecords(takeStockPlanDifferenceMapper.listByPage(page, takeStockPlanDifference));
	}

	/**
	 * 生成盘盈盘亏单
	 * @param id
	 */
	@Override
	public void addTakeStockResult(String id) {
		TakeStockPlanDifference byId = this.getById(id);
		if (!TakeStockPlanStatusConstant.SUBMITTED.equals(byId.getDocumentStatus())) {
			throw new JeecgBootException("单据状态不是已提交，不能生成盘盈盘亏单");
		}
		if ("1".equals(byId.getGenerateFlag())) {
			throw new JeecgBootException("不能重复生成盘盈盘亏单");
		}
		// 更新是否生成盘盈或盘亏单状态
		byId.setGenerateFlag("1");
//		byId.setDocumentStatus("3");

		List<TakeStockPlanDifferenceMaterial> list = takeStockPlanDifferenceMaterialMapper.selectList(new LambdaQueryWrapper<TakeStockPlanDifferenceMaterial>()
				.eq(TakeStockPlanDifferenceMaterial::getTakeStockPlanDifferenceId, id));
		List<String> inventoryProfits = new ArrayList<>();    //盘盈单
		List<String> inventoryLosses = new ArrayList<>();    //盘亏单
		for (TakeStockPlanDifferenceMaterial material : list) {
			if (StringUtils.isNotBlank(material.getInventoryProfit()) && !"0".equals(material.getInventoryProfit())) {
				inventoryProfits.add(material.getId());
			}
			if (StringUtils.isNotBlank(material.getInventoryLoss()) && !"0".equals(material.getInventoryLoss())) {
				inventoryLosses.add(material.getId());
			}
		}
		// 盘盈单
		if (CollectionUtils.isNotEmpty(inventoryProfits)) {
			TakeStockResult inventoryProfit = new TakeStockResult();
			inventoryProfit.setCode(FillRuleUtil.executeRule(FillRuleConstant.INVENTORY_PROFIT, new JSONObject()).toString());
			inventoryProfit.setTakeStockPlanDifferenceId(id);
			inventoryProfit.setType(TakeStockResultConstant.INVENTORY_PROFIT);
			inventoryProfit.setTakeStockPlanDifferenceMaterialId(StringUtils.join(inventoryProfits, ","));
			inventoryProfit.setDocumentStatus(TakeStockPlanStatusConstant.SUBMITTED);
			LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
			inventoryProfit.setOrganization(sysUser.getOrgCode());
			takeStockResultService.save(inventoryProfit);
			byId.setInventoryGainId(inventoryProfit.getId());
		}
		// 盘亏单
		if (CollectionUtils.isNotEmpty(inventoryLosses)) {
			TakeStockResult inventoryLoss = new TakeStockResult();
			inventoryLoss.setCode(FillRuleUtil.executeRule(FillRuleConstant.INVENTORY_LOSS, new JSONObject()).toString());
			inventoryLoss.setTakeStockPlanDifferenceId(id);
			inventoryLoss.setType(TakeStockResultConstant.INVENTORY_LOSS);
			inventoryLoss.setTakeStockPlanDifferenceMaterialId(StringUtils.join(inventoryLosses, ","));
			inventoryLoss.setDocumentStatus(TakeStockPlanStatusConstant.SUBMITTED);
			LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
			inventoryLoss.setOrganization(sysUser.getOrgCode());
			takeStockResultService.save(inventoryLoss);
			byId.setInventoryLossId(inventoryLoss.getId());
		}

		this.updateById(byId);
	}

	/**
	 * 导入物料明细
	 * @return
	 */
	@Override
	public Result<List<TakeStockPlanDifferenceMaterial>> importExcel(MultipartFile file, String takeStockPlanId, String takeStockPlanDifferenceId) {
		if (ObjectUtil.isNotEmpty(file)) {
			if (!file.getOriginalFilename().endsWith(".xlsx") || file.getOriginalFilename().endsWith(".xlx")) {
				return Result.error("文件格式错误！");
			}
		}
		ImportParams params = new ImportParams();
		params.setTitleRows(0);
		params.setHeadRows(1);
		params.setNeedSave(true);
		try {
			List<TakeStockPlanDifferenceMaterial> materials = new ArrayList<>();
			String organization = "";
			if (StringUtils.isNotBlank(takeStockPlanDifferenceId)) {
				materials = takeStockPlanDifferenceMaterialService.selectByMainId(takeStockPlanDifferenceId);
				organization = this.getById(takeStockPlanDifferenceId).getOrganization();
			} else {
				TakeStockPlanExecuteMaterialVO difference = takeStockPlanExecuteService.difference(takeStockPlanId);
				for (TakeStockPlanExecuteMaterial material : difference.getTakeStockPlanExecuteMaterialList()) {
					TakeStockPlanDifferenceMaterial bean = BeanUtil.toBean(material, TakeStockPlanDifferenceMaterial.class);
					materials.add(bean);
				}
				organization = takeStockPlanService.getById(takeStockPlanId).getOrganization();
			}

			List<TakeStockPlanDifferenceMaterial> list = ExcelImportUtil.importExcel(file.getInputStream(), TakeStockPlanDifferenceMaterial.class, params);
			List<String> errorLines = new ArrayList<>();
			List<TakeStockPlanDifferenceMaterial> successList = new ArrayList<>();
			for (int i = 0; i < list.size(); i++) {
				TakeStockPlanDifferenceMaterial material = list.get(i);
				if (StringUtils.isBlank(material.getMaterialCode()) || StringUtils.isBlank(material.getWmsBasicWarehouseId()) || StringUtils.isBlank(material.getRealCount())) {
					errorLines.add("第" + (i+2) + "行有必填字段未填");
					continue;
				}
				if (material.getRealCount().startsWith("-") || (StringUtils.isNotBlank(material.getRealCountAssistant()) && material.getRealCountAssistant().startsWith("-"))) {
					errorLines.add("第" + (i+2) + "行实盘数量和实盘数量(辅单位)不能填负数");
					continue;
				}
				// 批次号
				if (StringUtils.isNotBlank(material.getBatchCode())) {
					// 判断重复
					List<TakeStockPlanDifferenceMaterial> collect = materials.stream().filter(a -> Objects.equals(material.getBatchCode(), a.getBatchCode())).collect(Collectors.toList());
					if (CollectionUtils.isNotEmpty(collect)) {
						// 重复则覆盖实盘数量、实盘数量（辅单位）
						collect.get(0).setRealCount(material.getRealCount());
						collect.get(0).setRealCountAssistant(material.getRealCountAssistant());
						successList.add(collect.get(0));
						continue;
					}
					List<WmsRepertory> repertories = repertoryMapper.selectList(new LambdaQueryWrapper<WmsRepertory>()
							.eq(WmsRepertory::getBatchCode, material.getBatchCode()));
					if (CollectionUtils.isNotEmpty(repertories)) {
						BeanUtil.copyProperties(repertories.get(0), material);
						material.setRepertoryId(repertories.get(0).getId());
					} else {
						material.setStockQuantity(new BigDecimal("0"));
					}
				} else {
					// 判断重复
					List<TakeStockPlanDifferenceMaterial> collect = materials.stream().filter(a -> Objects.equals(material.getMaterialCode(), a.getMaterialCode())
							&& Objects.equals(material.getWmsBasicWarehouseId(), a.getWmsBasicWarehouseId())
							&& Objects.equals(material.getWmsBasicWarehouseAreaId(), a.getWmsBasicWarehouseAreaId())
							&& Objects.equals(material.getWmsBasicWarehouseAreaLocationId(), a.getWmsBasicWarehouseAreaLocationId())).collect(Collectors.toList());
					if (CollectionUtils.isNotEmpty(collect)) {
						// 重复则覆盖实盘数量、实盘数量（辅单位）
						collect.get(0).setRealCount(material.getRealCount());
						collect.get(0).setRealCountAssistant(material.getRealCountAssistant());
						successList.add(collect.get(0));
						continue;
					}
					List<WmsRepertory> repertories = repertoryMapper.selectList(new LambdaQueryWrapper<WmsRepertory>()
							.eq(WmsRepertory::getMaterialCode, material.getMaterialCode())
							.eq(WmsRepertory::getWmsBasicWarehouseId, material.getWmsBasicWarehouseId())
							.eq(WmsRepertory::getWmsBasicWarehouseAreaId, material.getWmsBasicWarehouseAreaId())
							.eq(WmsRepertory::getWmsBasicWarehouseAreaLocationId, material.getWmsBasicWarehouseAreaLocationId()));
					if (CollectionUtils.isNotEmpty(repertories)) {
						material.setStockQuantity(repertories.get(0).getStockQuantity());
						material.setStockQuantitySub(repertories.get(0).getStockQuantitySub());
					} else {
						material.setStockQuantity(new BigDecimal("0"));
					}
				}
				// 计算盘盈盘亏
				BigDecimal subtract = new BigDecimal(material.getRealCount()).subtract(material.getStockQuantity());
				if (subtract.compareTo(new BigDecimal("0")) == 1) {
					material.setResult("1");
					material.setInventoryProfit(subtract.stripTrailingZeros().toPlainString());
				} else if (subtract.compareTo(new BigDecimal("0")) == -1) {
					material.setResult("2");
					material.setInventoryLoss(subtract.abs().stripTrailingZeros().toPlainString());
				} else {
					material.setResult("4");
				}
				// 计算盘盈盘亏辅单位
				if (material.getStockQuantitySub() == null) {
					material.setStockQuantitySub(new BigDecimal("0"));
				}
				if (StringUtils.isNotBlank(material.getRealCountAssistant()) && material.getStockQuantitySub() != null) {
					BigDecimal sub = new BigDecimal(material.getRealCountAssistant()).subtract(material.getStockQuantitySub());
					if (sub.compareTo(new BigDecimal("0")) == 1) {
						material.setInventoryProfitAssistant(sub.stripTrailingZeros().toPlainString());
					} else if (sub.compareTo(new BigDecimal("0")) == -1) {
						material.setInventoryLossAssistant(sub.abs().stripTrailingZeros().toPlainString());
					}
				}
				if (StringUtils.isBlank(material.getRepertoryId())) {
					// 物料
					BasicMaterial byCode = basicMaterialService.getByCode(material.getMaterialCode());
					if (byCode == null) {
						errorLines.add("第" + (i+2) + "行数据物料编码信息不存在");
						continue;
					}
					material.setMaterialId(byCode.getId());
					material.setMaterialName(byCode.getName());
					material.setSpecification(byCode.getSpecification());
					material.setWmsBasicUnitId(byCode.getInventoryUnitId());
					material.setUnitSub(byCode.getAssistantUnitId());
					// 仓库校验
					WmsBasicWarehouse warehouse = warehouseMapper.selectById(material.getWmsBasicWarehouseId());
					if (warehouse == null) {
						errorLines.add("第" + (i+2) + "行数据仓库信息不存在");
						continue;
					}
					if (!ObjectUtil.equal(warehouse.getSysOrgCode(), organization)) {
						errorLines.add("第" + (i+2) + "行数据中该组织下不存在该仓库");
						continue;
					}
					if ("N".equals(warehouse.getIsUseArea())) {
						material.setWmsBasicWarehouseAreaId(null);
						material.setWmsBasicWarehouseAreaLocationId(null);
					} else {
						if (StringUtils.isNotBlank(material.getWmsBasicWarehouseAreaId())) {
							WmsBasicWarehouseArea area = warehouseAreaMapper.selectById(material.getWmsBasicWarehouseAreaId());
							if (area == null) {
								errorLines.add("第" + (i + 2) + "行数据库区信息不存在");
								continue;
							}
							List<WmsBasicWarehouseArea> areas = warehouseAreaMapper.selectList(new LambdaQueryWrapper<WmsBasicWarehouseArea>()
									.eq(WmsBasicWarehouseArea::getName, area.getName())
									.eq(WmsBasicWarehouseArea::getWmsBasicWarehouseId, material.getWmsBasicWarehouseId()));
							if (CollectionUtils.isEmpty(areas)) {
								errorLines.add("第" + (i + 2) + "行数据库区信息不存在");
								continue;
							}
							material.setWmsBasicWarehouseAreaId(areas.get(0).getId());
							if (!"0".equals(areas.get(0).getIsUseLocation())) {
								if (StringUtils.isNotBlank(material.getWmsBasicWarehouseAreaLocationId())) {
									WmsBasicWarehouseAreaLocation location = warehouseAreaLocationMapper.selectById(material.getWmsBasicWarehouseAreaLocationId());
									if (location == null) {
										errorLines.add("第" + (i + 2) + "行数据库位信息不存在");
										continue;
									}
									List<WmsBasicWarehouseAreaLocation> locations = warehouseAreaLocationMapper.selectList(new LambdaQueryWrapper<WmsBasicWarehouseAreaLocation>()
											.eq(WmsBasicWarehouseAreaLocation::getName, location.getName())
											.eq(WmsBasicWarehouseAreaLocation::getWmsBasicWarehouseAreaId, material.getWmsBasicWarehouseAreaId()));
									if (CollectionUtils.isEmpty(locations)) {
										errorLines.add("第" + (i + 2) + "行数据库位信息不存在");
										continue;
									}
									if ("1".equals(locations.get(0).getStatus())) {
										material.setWmsBasicWarehouseAreaLocationId(locations.get(0).getId());
									} else {
										material.setWmsBasicWarehouseAreaLocationId(null);
									}
								}
							} else {
								material.setWmsBasicWarehouseAreaLocationId(null);
							}
						}
					}
				}
				successList.add(material);
			}
			Result<List<TakeStockPlanDifferenceMaterial>> r = new Result();
			r.setSuccess(true);
			r.setCode(CommonConstant.SC_OK_200);
			r.setResult(successList);
			if (errorLines.size() > 0) {
				r.setSuccess(false);
				r.setCode(CommonConstant.SC_INTERNAL_SERVER_ERROR_500);
				r.setMessage(StringUtils.join(errorLines, "，"));
			} else {
				r.setMessage("文件导入成功！");
			}
			return r;
		} catch (Exception e) {
			log.error(e.getMessage(),e);
			return Result.error("文件导入失败:"+e.getMessage());
		} finally {
			try {
				file.getInputStream().close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

}
